package com.logic.comment.util;

import cn.hutool.extra.spring.SpringUtil;
import com.logic.comment.exection.LoginException;
import com.comment.exception.ServiceException;
import com.comment.pojo.domain.logic.domain.Player;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import org.springframework.data.redis.core.ValueOperations;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * jwt工具类
 */
public class JwtUtils {
    private final static RedisUtils redisUtil = SpringUtil.getBean(RedisUtils.class);
    // 使用uuid生成密钥
    private final static String secret = "202cb962ac59075b964b07152d234b70";
    // 用户数据的key
    private final static String usernameKey = "usernameKey";
    private static final String USER_LONGIN_KEY = "player:%d:loginKey";

    public static String createJwtToken(String username) {
        try {
            // 创建头部对象
            JWSHeader jwsHeader =
                    new JWSHeader.Builder(JWSAlgorithm.HS256)       // 加密算法
                            .type(JOSEObjectType.JWT) // 静态常量
                            .build();

            // 创建载荷
            Map<String, Object> map = new HashMap<String, Object>();
            map.put(usernameKey, username);
            Payload payload = new Payload(map);

            // 创建签名器
            JWSSigner jwsSigner = new MACSigner(secret);// 密钥

            // 创建签名
            JWSObject jwsObject = new JWSObject(jwsHeader, payload);// 头部+载荷
            jwsObject.sign(jwsSigner);// 再+签名部分

            // 生成token字符串
            return jwsObject.serialize();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static boolean verify(String jwtStr) {
        try {
            JWSObject jwsObject = JWSObject.parse(jwtStr);
            JWSVerifier jwsVerifier = new MACVerifier(secret);
            return jwsObject.verify(jwsVerifier);
        } catch (Exception e) {
            return false;
        }
    }

    public static void verifyUserToken(String token) {
        Long uid = JwtUtils.getPlayerId(token);
        String key = String.format(USER_LONGIN_KEY, uid);
        String rightToken = (String) redisUtil.get(key);
        if (!Objects.equals(rightToken, token)) {
            throw new LoginException("登录令牌不匹配,请重新登录");
        }
        // 续期
        redisUtil.set(key, token, 2, TimeUnit.HOURS);
    }


    /**
     * 从token中解析出用户名
     *
     * @param jwtStr token
     * @return 登录人ID和账号
     */
    public static String getUserNameFormJwt(String jwtStr) {
        try {
            JWSObject jwsObject = JWSObject.parse(jwtStr);
            Map<String, Object> map = jwsObject.getPayload().toJSONObject();
            return (String) map.get(usernameKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Long getPlayerId(String jwtStr) {
        String[] split = Objects.requireNonNull(JwtUtils.getUserNameFormJwt(jwtStr)).split(",");
        if (split.length < 1) {
            throw new ServiceException("玩家id为空");
        }
        return Long.valueOf(split[0]);
    }

    public static String getServeKey(String jwtStr) {
        String[] split = Objects.requireNonNull(JwtUtils.getUserNameFormJwt(jwtStr)).split(",");
        if (split.length != 2) {
            throw new ServiceException("服务器密钥为空");
        }
        return split[1];
    }

    public static String getPlayerName(String jwtStr) {
        String[] split = Objects.requireNonNull(JwtUtils.getUserNameFormJwt(jwtStr)).split(",");
        if (split.length != 2) {
            return "";
        }
        return split[1];
    }

    public static String getToken(Long playerId) {
        ValueOperations<Object, Object> bean = SpringUtil.getBean("valueOperations");
        return (String) bean.get(String.format("player:%d:loginKey", playerId));
    }

    public static String updateJwtToken(Player account) {
        String jwtToken = createJwtToken(account.getUid() + "," + account.getNickname());
        if (jwtToken == null) {
            throw new ServiceException("生成token失败");
        } else {
            String key = String.format(USER_LONGIN_KEY, account.getUid());
            ValueOperations<Object, Object> bean = SpringUtil.getBean("valueOperations");
            bean.set(key, jwtToken, 1L, TimeUnit.DAYS);
            return jwtToken;
        }
    }


}